#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "my_json_parse.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "my_dev_net_config.h"
#include "esp_wifi.h"
#include "esp_http_server.h"
#include "my_http_server.h"
#include "my_ota.h"
#include "my_dev_info.h"
#include "my_dev_config.h"
#include "my_dev_info.h"
#include "esp_ble_mesh_networking_api.h"

httpd_handle_t stream_httpd = NULL;
httpd_handle_t gateway_httpd = NULL;

static const char* TAG = "web_server";


/** 在字符串中查询特定字符位置索引
* const char *str ，字符串
* char c，要查找的字符
*/
int num_strchr(const char *str, char c) // 
{
    const char *pindex = strchr(str, c);
    if (NULL == pindex){
        return -1;
    }
    return pindex - str;
}

/* 解码
* const char * base64 码字
* uint8_t * dedata， 解码恢复的数据
*/
int base64_decode(const char * base64, uint8_t * dedata)
{
    const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    int i = 0, j=0;
    int trans[4] = {0,0,0,0};
    for (;base64[i]!='\0';i+=4){
        // 每四个一组，译码成三个字符
        trans[0] = num_strchr(base64char, base64[i]);
        trans[1] = num_strchr(base64char, base64[i+1]);
        // 1/3
        dedata[j++] = ((trans[0] << 2) & 0xfc) | ((trans[1]>>4) & 0x03);

        if (base64[i+2] == '='){
            continue;
        }
        else{
            trans[2] = num_strchr(base64char, base64[i + 2]);
        }
        // 2/3
        dedata[j++] = ((trans[1] << 4) & 0xf0) | ((trans[2] >> 2) & 0x0f);

        if (base64[i + 3] == '='){
            continue;
        }
        else{
            trans[3] = num_strchr(base64char, base64[i + 3]);
        }

        // 3/3
        dedata[j++] = ((trans[2] << 6) & 0xc0) | (trans[3] & 0x3f);
    }

    dedata[j] = '\0';

    return 0;
}




static esp_err_t index_handler(httpd_req_t *req)
{
    extern const unsigned char index_index_html_gz_start[] asm("_binary_index_html_gz_start");
    extern const unsigned char index_index_html_gz_end[] asm("_binary_index_html_gz_end");
    size_t index_index_html_gz_len = index_index_html_gz_end - index_index_html_gz_start;
    

    //  ext/html 响应数据类型
    httpd_resp_set_type(req, "text/html");
    httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
    return httpd_resp_send(req, (const char *)index_index_html_gz_start, index_index_html_gz_len);
}


/* web server登录界面(当前版本未使用，保留此功能)
*　user:admin passwd:admin
*  当前未使用base64解密，原因：此版本界面没有涉及到修改用户名和密码选项，所以是直接比较
*  用户名和密码编码后的字符串
*/
static esp_err_t master_handler(httpd_req_t *req)
{
    
    size_t len = httpd_req_get_hdr_value_len(req,"Authorization");
    // uint8_t data[50];
    if(len == 0){
        ESP_LOGE(TAG,"no finde key Authorization\n");
        httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"Secure Area\"");
        return httpd_resp_send_err(req, 401, NULL);
    }else{
        char valer[100] = {0};
        httpd_req_get_hdr_value_str(req,"Authorization",valer,len);
        ESP_LOGI(TAG,"base64 = %s\n", valer);
        if(strcmp(valer,"Basic YWRtaW46YWRtaW4") == 0)
        {
            ESP_LOGI(TAG, "userName And Passwd true");
            return index_handler(req);
        }
        return httpd_resp_send_err(req, 401, NULL);
    }
}

//解析http请求头部信息
static esp_err_t parse_top_info(httpd_req_t *req, char *obuf)
{
    char *buf = NULL;
    size_t buf_len = 0;
    
    //获取请求URL字符串长度
    buf_len = httpd_req_get_url_query_len(req) + 1;
    if (buf_len > 1) {
        buf = (char *)malloc(buf_len);
        if (!buf) {
            //发送http 500消息
            httpd_resp_send_500(req);
            return ESP_FAIL;
        }
        //获取请求网址的字符串
        if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
            sprintf(obuf,buf);
            free(buf);
            return ESP_OK;
        }
        free(buf);
    }
    httpd_resp_send_404(req);
    return ESP_FAIL;
}

static esp_err_t parse_recv_info(httpd_req_t *req, char *obuf)
{
    char buffer[512];
    int  ret;
    /* Read data received in the request */
    ret = httpd_req_recv(req, buffer, sizeof(buffer));
    if (ret <= 0) {
        ESP_LOGE(TAG,"recv failed");
        if (ret == HTTPD_SOCK_ERR_TIMEOUT) {
            httpd_resp_send_408(req);
        }
        return ESP_FAIL;
    }

    sprintf(obuf, buffer);
    httpd_resp_send(req, obuf, strlen(obuf));
    return ESP_OK;
}

static void reboot_task(void *parm)
{
    //延时１ｓ等待服务器响应客户端的请求
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    esp_restart();
    vTaskDelete(NULL);
}

static void restore_task(void *parm)
{
    //延时１ｓ等待服务器响应客户端的请求
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    erase_flash_data();
    //删除节点信息
    if(ESP_OK != esp_ble_mesh_node_local_reset()){
        ESP_LOGE(TAG, "Delete Note Info Failed");
    }
    esp_restart();
    vTaskDelete(NULL);
}


static void ota_task(void *parm)
{
    //延时１ｓ等待服务器响应客户端的请求
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    //停止ＡＰ模
    ESP_LOGE(TAG,"stop wifi ap");
    esp_wifi_stop();
    basic_init();
    //等待网络连接
    wait_for_ip();
    ESP_LOGI(TAG,"connect to AP");
    my_ota();
    // ping_test();
    vTaskDelete(NULL);
}



static esp_err_t config_handler(httpd_req_t *req)
{
    char buf[50] = {0};  
    char value[256] = {0};
    // tmp_test(req);
    parse_top_info(req, buf);
    ESP_LOGI(TAG,"parse data: %s",buf);

    httpd_query_key_value(buf, "command", value, sizeof(value));
    // printf("value = %s\n",value);

    /****************************重启******************************/
    if(strcmp("reboot",value) == 0){
        ESP_LOGI(TAG,"reboot");
        xTaskCreate(reboot_task,"reboot_task",1024,NULL,5,NULL);
    }

    /**************************恢复出厂设置**************************/
     else if(strcmp("restore", value) == 0){
        ESP_LOGI(TAG,"restore");
        xTaskCreate(restore_task,"restore_task",1024,NULL,5,NULL);
    } 

    /**************************OTA升级**************************/
    else if(strcmp("ota", value) == 0){
        ESP_LOGI(TAG,"start oat task");
        xTaskCreate(ota_task,"ota_task",2048,NULL,5,NULL);
    }

    /*************************wifi配置***************************/
    else if(strcmp("wifi",value) == 0){
        char recv_buf[512];
        //获得设置参数,解析数据内容
        parse_recv_info(req,recv_buf);
        ESP_LOGI(TAG,"%s\n",recv_buf);
        //解析json数据
        parse_ap_data(recv_buf);
        //记录设备下次启动不是为第一次启动
        first_start_write(!DEV_FIRST_START);
    }

    /*********************MQTT client配置************************/
    else if(strcmp("client",value) == 0){
        char recv_buf[1024];
        //获得设置参数,解析数据内容
        parse_recv_info(req,recv_buf);
        ESP_LOGI(TAG,"%s\n",recv_buf);
        //解析json数据
        parse_mqtt_client_data(recv_buf);
        //记录设备下次启动不是为第一次启动
        first_start_write(!DEV_FIRST_START);
    }

    /*********************节点配置************************/
    else if(strcmp("note",value) == 0){
        ESP_LOGI(TAG,"note set\r\n");
        char recv_buf[64];
        //获得设置参数,解析数据内容
        parse_recv_info(req,recv_buf);
        ESP_LOGI(TAG,"####%s\n",recv_buf);
        parse_note_data(recv_buf);
    }
    
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, NULL, 0);
}


static esp_err_t icon_handler(httpd_req_t *req)
{
    
    extern const unsigned char index_aithinker_png_gz_start[] asm("_binary_aithinker_png_gz_start");
    extern const unsigned char index_aithinker_png_gz_end[] asm("_binary_aithinker_png_gz_end");
    size_t index_aithinker_png_gz_len = index_aithinker_png_gz_end - index_aithinker_png_gz_start;

    httpd_resp_set_type(req, "image/png");
    httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
    return httpd_resp_send(req, (const char *)index_aithinker_png_gz_start, index_aithinker_png_gz_len);
}

static esp_err_t back_handler(httpd_req_t *req)
{
    extern const unsigned char index_mbl_jpg_gz_start[] asm("_binary_mbl_jpg_gz_start");
    extern const unsigned char index_mbl_jpg_gz_end[] asm("_binary_mbl_jpg_gz_end");
    size_t index_mbl_jpg_gz_len = index_mbl_jpg_gz_end - index_mbl_jpg_gz_start;

    httpd_resp_set_type(req, "image/jpg");
    httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
    return httpd_resp_send(req, (const char *)index_mbl_jpg_gz_start, index_mbl_jpg_gz_len);
}

static esp_err_t webserver_icon_handler(httpd_req_t *req)
{
    
    extern const unsigned char index_aithinker_icon_ico_gz_start[] asm("_binary_aithinker_icon_ico_gz_start");
    extern const unsigned char index_aithinker_icon_ico_gz_end[] asm("_binary_aithinker_icon_ico_gz_end");
    size_t index_aithinker_icon_ico_gz_len = index_aithinker_icon_ico_gz_end - index_aithinker_icon_ico_gz_start;

    httpd_resp_set_type(req, "image/ico");
    httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
    return httpd_resp_send(req, (const char *)index_aithinker_icon_ico_gz_start, index_aithinker_icon_ico_gz_len);
}


static esp_err_t systemInfo_handler(httpd_req_t *req)
{
    static char json_response[1024];
    char *p = json_response;
    


    uint8_t ssid_name[32] = {0};
    //物理mac地址
    uint8_t mac_addr[6] = {0};
    //获取模块mac地址
    esp_read_mac(mac_addr, ESP_MAC_WIFI_STA);  
    // printf("%02x%02X%02X%02x%02X%02X\n",mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);   
    sprintf((char *)ssid_name,"aithinkerGW01_%02X%02X%02X",mac_addr[3],mac_addr[4],mac_addr[5]);
    p += sprintf(p, "{\"ssid\":\"%s\"", ssid_name);

    p += sprintf(p, ",\"gw\":\"192.168.4.1\"");
    p += sprintf(p, ",\"mask\":\"255.255.255.0\"");
    p += sprintf(p, ",\"version\":\"%s\"",FW_VERSION);
    p += sprintf(p, ",\"mac\":\"%02X%02X%02X%02X%02X%02X\"}",mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);

    *p++ = 0;

    ESP_LOGI(TAG,"%s\n",p);
    httpd_resp_set_type(req, "application/json");
    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
    return httpd_resp_send(req, json_response, strlen(json_response));
}


static esp_err_t ble_handler(httpd_req_t *req)
{
    ESP_LOGI(TAG,"ble gateway\n");
    uint8_t dev_work = BLE_MODEL;
    write_dev_work_model(dev_work);
    index_handler(req);
    systemInfo_handler(req);
    return httpd_resp_set_status(req, HTTPD_200);
    // return ESP_OK;
}


static esp_err_t wifi_handler(httpd_req_t *req)
{
    ESP_LOGI(TAG,"wifi gateway\n");
    uint8_t dev_work = WIFI_MODEL;
    write_dev_work_model(dev_work);
    index_handler(req);
    systemInfo_handler(req);
    return httpd_resp_set_status(req, HTTPD_200);
    // return ESP_OK;
}

//根目录界面
httpd_uri_t index_uri = {
    .uri = "/",
    .method = HTTP_GET,
    .handler = index_handler,
    // .handler = master_handler,
    .user_ctx = NULL
};

//界面图片
httpd_uri_t icon_uri = {
    .uri = "/img/aithinker.png",
    .method = HTTP_GET,
    .handler = icon_handler,
    .user_ctx = NULL
};
//界面背景
httpd_uri_t back_uri = {
    .uri = "/img/mbl.jpg",
    .method = HTTP_GET,
    .handler = back_handler,
    .user_ctx = NULL
};
//网页图标
httpd_uri_t sebserver_uri = {
    .uri = "/img/aithinker-icon.ico",
    .method = HTTP_GET,
    .handler = webserver_icon_handler,
    .user_ctx = NULL
};

httpd_uri_t systemInfo_uri = {
    .uri = "/systemInfo",
    .method = HTTP_GET,
    .handler = systemInfo_handler,
    .user_ctx = NULL
};
    
//客户端请求的数据
httpd_uri_t config_uri = {
    .uri = "/config",
    .method = HTTP_POST,
    .handler = config_handler,
    .user_ctx = NULL
};

httpd_uri_t ble_uri = {
    .uri = "/ble",
    .method = HTTP_GET,
    .handler = ble_handler,
    .user_ctx = NULL
};

httpd_uri_t wifi_uri = {
    .uri = "/wifi",
    .method = HTTP_GET,
    .handler = wifi_handler,
    .user_ctx = NULL
};


// aithinker-icon.ico.gz

httpd_handle_t start_webserver(void)
{
    //http服务实例句柄
    httpd_handle_t server = NULL;
    //默认的配置参数
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.stack_size = 8192;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK) {
        // Set URI handlers
        ESP_LOGI(TAG, "Registering URI handlers");
        httpd_register_uri_handler(server, &index_uri); //根界面
        httpd_register_uri_handler(server, &icon_uri);  //图标
        httpd_register_uri_handler(server, &sebserver_uri);//网页图标
        // httpd_register_uri_handler(server, &back_uri);  //背景
        httpd_register_uri_handler(server, &systemInfo_uri);  //请求系统参数
        httpd_register_uri_handler(server, &config_uri);//客户端请求数据
        httpd_register_uri_handler(server, &ble_uri);   //蓝牙网关
        httpd_register_uri_handler(server, &wifi_uri);  //wifi网关
        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}

